// MqttRetainedMessageScheduler.java
package com.lingyun.mqttserver.config;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lingyun.mqttserver.dao.mapper.DeviceInfoMapper;
import com.lingyun.mqttserver.dao.mapper.LowerComputerVariableMapper;
import com.lingyun.mqttserver.dao.mapper.MqttScreenVariableMappingMapper;
import com.lingyun.mqttserver.dao.mapper.MqttScreenVariableMappingVariableMapper;
import com.lingyun.mqttserver.dao.pojo.DeviceInfo;
import com.lingyun.mqttserver.dao.pojo.LowerComputerVariable;
import com.lingyun.mqttserver.dao.pojo.MqttScreenVariableMapping;
import com.lingyun.mqttserver.service.impl.MqttMessageService;
import com.lingyun.mqttserver.util.JSONUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import lombok.extern.slf4j.Slf4j;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
public class MqttRetainedMessageScheduler {

    @Autowired
    private MqttMessageService mqttMessageService;
    @Autowired
    private MqttScreenVariableMappingMapper mqttScreenVariableMappingMapper;
    @Autowired
    private LowerComputerVariableMapper lowerComputerVariableMapper;
    @Autowired
    private MqttScreenVariableMappingVariableMapper mqttScreenVariableMappingVariableMapper;
    @Autowired
    private DeviceInfoMapper deviceInfoMapper;

    @Autowired
    private JdbcTemplate jdbcTemplate;

//    @Autowired
//    private DeviceDataService deviceDataService; // 假设有这个服务

    /**
     * 每5分钟发送一次所有下位机数据的保留消息
     * fixedRate: 执行间隔时间，单位毫秒（5分钟 = 300000毫秒）
     */
    @Scheduled(fixedRate = 300000)
    public void scheduledSendRetainedMessages() {
        log.info("开始执行定时发送保留消息任务 - {}", LocalDateTime.now());
        try {
            // 这里调用业务逻辑获取设备数据并发送保留消息
            pushMQTT();
        } catch (Exception e) {
            log.error("定时发送保留消息任务异常: {}", e.getMessage(), e);
        }
    }

    /**
     * 每天凌晨2点执行一次全量数据同步
     */
    @Scheduled(cron = "0 0 2 * * ?")
    public void dailyFullDataSync() {
        log.info("开始执行每日全量数据同步任务 - {}", LocalDateTime.now());
        pushMQTT();
        try {
//            deviceDataService.sendAllDeviceRetainedData();
            log.info("每日全量数据同步任务完成 - {}", LocalDateTime.now());
        } catch (Exception e) {
            log.error("每日全量数据同步任务异常: {}", e.getMessage(), e);
        }
    }


    /**
     * 定时更新的数据
     */
//    private void pushMQTT(){
//        // 找到所有已被分配的mqtt屏幕
//        HashSet<Integer> screenIds = new HashSet<>();
//        // 将所有的索引拿到后端来
//        List<MqttScreenVariableMapping> mqttScreenVariableMappings = mqttScreenVariableMappingMapper.selectList(null);
//        mqttScreenVariableMappings.forEach(mqttScreenVariableMapping -> screenIds.add(mqttScreenVariableMapping.getScreenId()));
//
//        // 存储多个屏幕要更新的变量
//        HashMap<String, Object> screenVariable = new HashMap<>();
//        // 通过屏幕id获取每个连接的下位机的变量
//        screenIds.forEach(screenId -> {
//            // 获取Mqtt屏幕连接的下位机变量
//            HashMap<String, Object> lowerComputer = new HashMap<>();
//            mqttScreenVariableMappings.stream().filter(mqttScreenVariableMapping -> mqttScreenVariableMapping.getScreenId().equals(screenId)).forEach(mqttScreenVariableMapping -> {
//                // 通过连接查询每个屏幕都有对应的变量的数据
//                List<Map<String, Object>> stringObjectMap = mqttScreenVariableMappingVariableMapper.selectVariablesWithValues(mqttScreenVariableMapping.getScreenId(), mqttScreenVariableMapping.getId(), mqttScreenVariableMapping.getLowerComputerId());
//                stringObjectMap.forEach(stringObjectMap1 -> {
//                    lowerComputer.put((String) stringObjectMap1.get("mqtt_variable_name"), stringObjectMap1.get("current_value"));
//                });
//            });
//            DeviceInfo deviceInfo = deviceInfoMapper.selectById(screenId);
//            screenVariable.put(deviceInfo.getHardwareAddress(), lowerComputer);
//        });
//
//        // 发送mqtt信息，设置保留消息
//        screenVariable.forEach((key, value) -> {
//            mqttMessageService.sendMessage(key + "/subcribe", value.toString(), true);
//        });
////        System.out.println(screenVariable);
//    }

    private void pushMQTT() {
        // 1. 获取所有屏幕ID
        List<MqttScreenVariableMapping> mappings = mqttScreenVariableMappingMapper.selectList(null);
        Set<Integer> screenIds = mappings.stream()
                .map(MqttScreenVariableMapping::getScreenId)
                .collect(Collectors.toSet());

        if (screenIds.isEmpty()) return;

        // 2. 单次查询所有数据
        List<Map<String, Object>> allData = selectBatchVariablesWithValues(new ArrayList<>(screenIds));

        // 3. 按屏幕分组处理
        Map<Integer, Map<String, Object>> screenData = allData.stream()
                .collect(Collectors.groupingBy(
                        data -> (Integer) data.get("screen_id"),
                        Collectors.toMap(
                                data -> (String) data.get("mqtt_variable_name"),
                                data -> data.get("current_value")
                        )
                ));

        // 4. 批量获取设备信息
        List<DeviceInfo> devices = deviceInfoMapper.selectBatchIds(new ArrayList<>(screenIds));
        Map<Integer, String> addressMap = devices.stream()
                .collect(Collectors.toMap(DeviceInfo::getId, DeviceInfo::getHardwareAddress));

        // 5. 发送MQTT
        for (Map.Entry<Integer, Map<String, Object>> entry : screenData.entrySet()) {
            Integer screenId = entry.getKey();
            Map<String, Object> variables = entry.getValue();
            String address = addressMap.get(screenId);

            if (address != null && !variables.isEmpty()) {
                mqttMessageService.sendMessage(address + "/subcribe",
                        JSONUtil.toJSON(variables), true);
            }
        }
    }

    private List<Map<String, Object>> selectBatchVariablesWithValues(List<Integer> screenIds) {
        if (screenIds.isEmpty()) {
            return new ArrayList<>();
        }

        String inClause = screenIds.stream()
                .map(String::valueOf)
                .collect(Collectors.joining(","));

        String sql = String.format("""
            SELECT 
                m.screen_id,
                m.mapping_id, 
                m.lower_computer_id,
                m.mqtt_variable_name,
                v.current_value
            FROM mqtt_screen_variable_mapping_variable m
            INNER JOIN lower_computer_variable v ON m.lower_variable_id = v.id
            WHERE m.screen_id IN (%s)
            ORDER BY m.screen_id, m.mapping_id
            """, inClause);

        return jdbcTemplate.queryForList(sql);
    }
}